package com.my.lock.v2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

/**
 * Created by ZhongGang
 * at 2018/7/27 10:27
 */
public class ReentrantLock {
    private static final Logger LOGGER = LoggerFactory.getLogger(ReentrantLock.class);

    private AtomicBoolean locked = new AtomicBoolean(false);//标识是否已有线程持有锁
    private Queue<Thread> waiters = new ConcurrentLinkedQueue<>();//等待获取锁的线程
    private Thread exclusiveThread = null;//持有锁的线程，用于可重入判断
    /**
     * 重入次数，用于可重入判断
     * 如果持有锁的线程嵌套调用同步方法，每嵌套一层该值就加1
     * 当释放锁的时候，每释放一次该值就减1，直到为0，表示没有线程再持有锁，此时其它线程可尝试获取锁
     */
    private int state = 0;

    public void lock() {
        if (this.locked.compareAndSet(false, true)) {//重要：将此判断替换为分布式原子操作就成了分布式锁
            this.exclusiveThread = Thread.currentThread();
            this.state += 1;
            LOGGER.info("execute thread: {}, state: {}", this.exclusiveThread, this.state);
        } else {
            Thread thread = Thread.currentThread();
            if (this.exclusiveThread != thread) {
                this.waiters.add(thread);
                LockSupport.park();//未持有锁的线程会在这里进入等待状态，直到调用unpark方法
                lock();
            } else {
                this.state += 1;
            }
        }
    }

    public void unlock() {
        this.state -= 1;
        LOGGER.info("current thread: {}, current state: {}", Thread.currentThread(), this.state);
        if (this.state == 0) {
            this.locked.set(false);
            this.exclusiveThread = null;
            Thread nextThread = this.waiters.poll();
            LockSupport.unpark(nextThread);
        }
    }
}
